<script>
  import JsonBox from '../json-box.vue'
  import { h } from 'vue'
  export default {
    name: 'JsonObject',
    props: {
      jsonValue: {
        type: Object,
        required: true,
      },
      keyName: {
        type: String,
        default: '',
      },
      depth: {
        type: Number,
        default: 0,
      },
      expand: Boolean,
      sort: Boolean,
      previewMode: Boolean,
    },
    emits: ['update:expand'],
    data() {
      return {
        value: {},
      }
    },
    computed: {
      ordered() {
        if (!this.sort) {
          return this.value
        }

        const ordered = {}
        Object.keys(this.value)
          .sort()
          .forEach((key) => {
            ordered[key] = this.value[key]
          })
        return ordered
      },
    },
    watch: {
      jsonValue(newVal) {
        this.setValue(newVal)
      },
    },
    mounted() {
      this.setValue(this.jsonValue)
    },
    methods: {
      setValue(val) {
        setTimeout(() => {
          this.value = val
        }, 0)
      },
      toggle() {
        this.$emit('update:expand', !this.expand)
        this.dispatchEvent()
      },
      dispatchEvent() {
        try {
          this.$el.dispatchEvent(new Event('resized'))
        } catch (e) {
          // handle IE not supporting Event constructor
          const evt = document.createEvent('Event')
          evt.initEvent('resized', true, false)
          this.$el.dispatchEvent(evt)
        }
      },
    },
    render() {
      let elements = []
      if (!this.previewMode && !this.keyName) {
        elements.push(
          h('span', {
            class: {
              'jv-toggle': true,
              open: !!this.expand,
            },
            onClick: this.toggle,
          })
        )
      }

      elements.push(
        h('span', {
          class: {
            'jv-item': true,
            'jv-object': true,
          },
          innerText: '{',
        })
      )

      if (this.expand) {
        for (let key in this.ordered) {
          // eslint-disable-next-line no-prototype-builtins
          if (this.ordered.hasOwnProperty(key)) {
            let value = this.ordered[key]
            elements.push(
              h(JsonBox, {
                key,
                style: {
                  display: !this.expand ? 'none' : undefined,
                },
                sort: this.sort,
                keyName: key,
                depth: this.depth + 1,
                value,
                previewMode: this.previewMode,
              })
            )
          }
        }
      }

      if (!this.expand && Object.keys(this.value).length) {
        elements.push(
          h('span', {
            style: {
              display: this.expand ? 'none' : undefined,
            },
            class: {
              'jv-ellipsis': true,
            },
            onClick: this.toggle,
            title: `click to reveal object content (keys: ${Object.keys(
              this.ordered
            ).join(', ')})`,
            innerText: '...',
          })
        )
      }

      elements.push(
        h('span', {
          class: {
            'jv-item': true,
            'jv-object': true,
          },
          innerText: '}',
        })
      )

      return h('span', elements)
    },
  }
</script>
